import os
import struct

from ctypes import c_uint32

DELTA = 0x9e3779b9
SUMATION = 0xc6ef3720
ROUNDS = 32
BLOCK_SIZE = 2 # number of 32-bit ints
KEY_SIZE = 4

class CryptTEA:
    encryptKey = [c_uint32(0x1c112415), c_uint32(0x64d4316f), c_uint32(0x32022061), c_uint32(0xb09944c0)]
    input = 'current_data/out.json'
    output = 'out.tea'

    def __init__(self, input = False, output = False):
        if (input != False):
            self.input = input
        if (output != False):
            self.output = output
        self.encrypt(self.input, self.output)

    def encrypt_block(self, block, key):
        assert len(block) == BLOCK_SIZE
        assert len(key) == KEY_SIZE
        sumation = c_uint32(0)
        delta = c_uint32(DELTA)
        for index in range(0, ROUNDS):
            sumation.value += delta.value
            block[0].value += ((block[1].value << 4) + key[0].value) ^ (block[1].value + sumation.value) ^ ((block[1].value >> 5) + key[1].value)
            block[1].value += ((block[0].value << 4) + key[2].value) ^ (block[0].value + sumation.value) ^ ((block[0].value >> 5) + key[3].value)
        return block

    def to_c_array(self, data):
        c_array = []
        char_array = [hex(ord(char))[2:] for char in data]
        for index in range(0, len(char_array), 4):
            block = char_array[index:index + 4]
            block.reverse()
            hex_value = '0x' + ''.join(block)
            c_array.append(c_uint32(int(hex_value, 16)))
        return c_array

    def to_string(self, c_array):
        output = ''
        for block in c_array:
            hex_string = hex(block.value)[2:-1]
            while (len(hex_string) < 8):
                hex_string = '0' + hex_string
            hex_list = []
            for index in range(0, len(hex_string), 2):
                hex_list.append(hex_string[index:index + 2])
            hex_list.reverse();
            hex_string = ''.join(hex_list)
            for index in range(0, len(hex_string), 2):
                byte = int('0x%s' % hex_string[index:index + 2], 16)
                output += chr(byte)
        return output

    def add_padding(self, data):
        dataSize = len(data)
        step = BLOCK_SIZE * KEY_SIZE
        paddingSize = 0
        if (dataSize % step != 0):
            paddingSize = step - dataSize % step
            dataSize += paddingSize
            n = paddingSize
            while (n > 0):
                data += '\0'
                n -= 1
        return data

    def encrypt_string(self, data, key):
        data = self.add_padding(data)
        data = self.to_c_array(data)
        cipher_text = []
        for index in range(0, len(data), 2):
            block = data[index:index + 2]
            block = self.encrypt_block(block, key)
            for uint in block:
                cipher_text.append(uint)
        return self.to_string(cipher_text)

    def encrypt(self, inS, outS):
        input = open(inS, 'rb')
        output = open(outS,  'wb')
        input.seek(0, 2)
        size = input.tell()
        input.seek(0, 0)
        output.write(struct.pack('<II10sI4sI', 26, 10, 'ENCRYPTED', 4, 'TEA', 1))
        buff = input.read()
        buff = self.encrypt_string(buff, self.encryptKey)
        output.write(buff)
        output.close()
        input.close()
        return

#crypter = CryptTEA()


